package com.jse.ee;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.security.Principal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;

import com.jse.Jse;
import com.jse.Lang;

import jakarta.servlet.AsyncContext;
import jakarta.servlet.DispatcherType;
import jakarta.servlet.ReadListener;
import jakarta.servlet.RequestDispatcher;
import jakarta.servlet.ServletConnection;
import jakarta.servlet.ServletContext;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletInputStream;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import jakarta.servlet.http.HttpUpgradeHandler;
import jakarta.servlet.http.Part;

public class JseServerRequest implements HttpServletRequest {
	
	private String characterEncoding="UTF-8";
	private int contentLength;
	private String contentType="text/html";
	private HashMap<String,Object> attributes=new HashMap<>();
	private HashMap<String,String> headers=new HashMap<>();
	private InputStream inputStream;
	private HashMap<String,String[]> parameters=new HashMap<String, String[]>();
	private String protocol;
	private String scheme;
	private String serverName;
	private int serverPort;
	private BufferedReader reader;
	String remoteHost;
	private Locale local=Locale.getDefault();
	protected final ArrayList<Locale> locales = new ArrayList<>();
	private boolean secure;
	String line0;
	String remoteAddr;
	int remotePort;
	private String localName;
	private String localAddr;
	int localPort;
	private HashMap<String,Part> parts=new HashMap<>();
	private String method;
	private StringBuffer requestURL;
	private String requestURI;
	private static final AtomicLong requestIdGenerator = new AtomicLong(0);
	private volatile String requestId = Long.toString(requestIdGenerator.getAndIncrement());
	private HashMap<String,Cookie> cookies=new HashMap<>();
	private String servletPath;
	private String queryString;
	private String requestedSessionId;
	

	public JseServerRequest(InputStream in) throws IOException {
		this.inputStream=in;
		this.reader=new BufferedReader(new InputStreamReader(in));
		parse(reader.readLine());
	}
	public JseServerRequest(InputStream in,BufferedReader reader,String line) throws IOException {
		this.inputStream=in;
		this.reader=reader;
		parse(line);
	}
	private void parse(String line0) throws IOException {
		if(line0==null) {return;}
		String[] line0s = line0.split(" ");method=line0s[0];requestURI=line0s[1];protocol=line0s[2];//协议
		scheme=protocol.equals("HTTP/1.1")?"http":"https";
		try{requestURI=URLDecoder.decode(requestURI,Jse.charset);}catch(IllegalArgumentException e){}
		this.requestURL=new StringBuffer(scheme).append("://").append(remoteHost).append(remotePort==80?"":":"+remotePort)
				.append(requestURI);
		var uri=requestURI.split("\\?");
		servletPath=uri[0].substring(getContextPath().length());
		if(requestURI.equals("/favicon.ico"))return;
		String line=null;
		while (!(line = reader.readLine()).isEmpty()) {var lines=line.split(": ");addHeader(lines[0], lines[1]);}
		if(uri.length>1) {
			queryString=uri[1];
			String[] pss=queryString.split("&");
			for (int i = 0; i < pss.length; i++) {
				var ps=pss[i].split("=");
				if(parameters.containsKey(ps[0])) {
					var arr=parameters.get(ps[0]);
					arr=Arrays.copyOf(arr,arr.length+1);
					arr[arr.length-1]=ps[1];
					parameters.put(ps[0],arr);
				}else {
					parameters.put(ps[0],new String[] {ps[1]});
				}
			}
		}
		if(requestedSessionId==null)requestedSessionId=Lang.uuid();
	}
	private void addHeader(String name,String value) {
//		System.out.println("header:"+name+" = "+value);
		switch (name) {
			case "Host"->{var host=value.split(":");remoteHost=host[0];remoteAddr=host[0];
			remotePort=host.length==1?80:Integer.valueOf(host[1]);}
			case "Cookie"->{//JSESSIONID
				var cks=value.split("; ");
				for (int i = 0; i < cks.length; i++) {
					var ck=cks[i].split("=");
					cookies.put(ck[0],new Cookie(ck[0],ck[1]));
					if(ck[0].equals("JSESSIONID")) {
						requestedSessionId=ck[1];
					}
				}
			}
		}
		headers.put(name, value);
	}
	
	@Override
	public Object getAttribute(String name) {
		return attributes.get(name);
	}

	@Override
	public Enumeration<String> getAttributeNames() {return Collections.enumeration(attributes.keySet());}

	@Override
	public String getCharacterEncoding() {
		return characterEncoding;
	}

	@Override
	public void setCharacterEncoding(String env) throws UnsupportedEncodingException {
		this.characterEncoding=env;
	}

	@Override
	public int getContentLength() {return contentLength;}

	@Override
	public long getContentLengthLong() {return contentLength;}

	@Override
	public String getContentType() {return contentType;}

	@Override
	public ServletInputStream getInputStream() throws IOException {
		return new ServletInputStream() {
			
			@Override
			public int read() throws IOException {
				return inputStream.read();
			}
			
			@Override
			public void setReadListener(ReadListener readListener) {
				// TODO Auto-generated method stub
			}
			
			@Override
			public boolean isReady() {
				// TODO Auto-generated method stub
				return false;
			}
			
			@Override
			public boolean isFinished() {
				// TODO Auto-generated method stub
				return false;
			}
		};
	}

	@Override
	public String getParameter(String name) {var o=parameters.get(name);return (o!=null&&o.length>0)?o[0]:null;}

	@Override
	public Enumeration<String> getParameterNames() {return Collections.enumeration(parameters.keySet());}

	@Override
	public String[] getParameterValues(String name) {return parameters.get(name);}

	@Override
	public Map<String, String[]> getParameterMap() {return parameters;}

	@Override
	public String getProtocol() {return protocol;}

	@Override
	public String getScheme() {return scheme;}

	@Override
	public String getServerName(){return serverName;}

	@Override
	public int getServerPort() {return serverPort;}

	@Override
	public BufferedReader getReader() throws IOException {return reader;}

	@Override
	public String getRemoteAddr() {return remoteAddr;}

	@Override
	public String getRemoteHost() {return remoteHost;}

	@Override
	public void setAttribute(String name, Object o) {attributes.put(name, o);}

	@Override
	public void removeAttribute(String name) {attributes.remove(name);}

	@Override
	public Locale getLocale() {return local;}

	@Override
	public Enumeration<Locale> getLocales() {return Collections.enumeration(locales);}

	@Override
	public boolean isSecure() {return secure;}

	@Override
	public RequestDispatcher getRequestDispatcher(String path) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public int getRemotePort() {return remotePort;}

	@Override
	public String getLocalName() {return localName;}

	@Override
	public String getLocalAddr() {return localAddr;}

	@Override
	public int getLocalPort() {return localPort;}

	@Override
	public ServletContext getServletContext() {return JseServer.ctx;}

	@Override
	public AsyncContext startAsync() throws IllegalStateException {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public AsyncContext startAsync(ServletRequest servletRequest, ServletResponse servletResponse)
			throws IllegalStateException {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public boolean isAsyncStarted() {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public boolean isAsyncSupported() {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public AsyncContext getAsyncContext() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public DispatcherType getDispatcherType() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public String getRequestId() {return requestId;}

	@Override
	public String getProtocolRequestId() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public ServletConnection getServletConnection() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public String getAuthType() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public Cookie[] getCookies() {
		// TODO Auto-generated method stub
//		private void parseCookies() {
//	        List<Cookie> cookieList = new ArrayList<>();
//	        String cookies = headerMap.get("cookie");
//	        if(cookies != null) {
//	            String[] pairs = StrUtil.split(cookies, ";");
//	            for(String pair : pairs) {
//	                if (StrUtil.isBlank(pair))
//	                    continue;
//	                String[] segs = StrUtil.split(pair,"=");
//	                String name = segs[0].trim();
//	                String value = segs[1].trim();
//	                Cookie cookie = new Cookie(name, value);
//	                cookieList.add(cookie);
//	            }
//	        }
//	        this.cookies = ArrayUtil.toArray(cookieList, Cookie.class);
//	    }
		return null;
	}

	@Override
	public long getDateHeader(String name) {
		// TODO Auto-generated method stub
		return 0;
	}

	@Override
	public String getHeader(String name) {return headers.get(name);}

	@Override
	public Enumeration<String> getHeaders(String name) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public Enumeration<String> getHeaderNames() {return Collections.enumeration(headers.keySet());}

	@Override
	public int getIntHeader(String name) {
		// TODO Auto-generated method stub
		return 0;
	}

	@Override
	public String getMethod() {return method;}

	@Override
	public String getPathInfo() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public String getPathTranslated() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public String getContextPath() {return getServletContext().getContextPath();}

	@Override
	public String getQueryString() {return queryString;}

	@Override
	public String getRemoteUser() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public boolean isUserInRole(String role) {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public Principal getUserPrincipal() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public String getRequestedSessionId() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public String getRequestURI() {return requestURI;}

	@Override
	public StringBuffer getRequestURL() {return requestURL;}

	@Override
	public String getServletPath() {return servletPath;}

	@Override
	public HttpSession getSession(boolean create) {
		var session=SessionManager.get(requestedSessionId);
		if(create&&session==null) {
			session=new JseHttpSession(requestedSessionId);
			SessionManager.SESSIONS.put(requestedSessionId,session);
		}
		return session;
	}

	@Override
	public HttpSession getSession() {
		return getSession(true);
	}
//	Arrays.stream(cookies).filter(cookie -> cookie.getName().equals("JSESSIONID")).map(Cookie::getValue).findFirst();

	@Override
	public String changeSessionId() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public boolean isRequestedSessionIdValid() {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public boolean isRequestedSessionIdFromCookie() {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public boolean isRequestedSessionIdFromURL() {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public boolean authenticate(HttpServletResponse response) throws IOException, ServletException {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public void login(String username, String password) throws ServletException {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void logout() throws ServletException {
		// TODO Auto-generated method stub
		
	}

	@Override
	public Collection<Part> getParts() throws IOException, ServletException {return parts.values();}

	@Override
	public Part getPart(String name) throws IOException, ServletException {return parts.get(name);}

	@Override
	public <T extends HttpUpgradeHandler> T upgrade(Class<T> handlerClass) throws IOException, ServletException {
		// TODO Auto-generated method stub
		return null;
	}
    

//	/**
//     * 生成sessionId
//     * 一：生成随机数
//     * 二：MD5加密
//     * 三：大写
//     * @return
//     */
//    public static synchronized String generateSessionId(){
//        String res;
//        byte[] bytes = RandomUtil.randomBytes(16);
//        res = new String(bytes);
//        res = SecureUtil.md5(res);
//        res = res.toUpperCase();
//        return res;
//    }
	
}
